import {ConditionBuilder} from '../conditions';
import {
  Entity,
  SQL_OPERATION_TYPE,
  SqlBuilderExtensions,
  SqlBuildResult,
  SqlOperationType,
  TableEntityMapping
} from "./types";
import {SqlExecuteResult, SqlExecutor} from "../execution";

/**
 * 插入构建器
 * 用于构建INSERT SQL语句
 */
export class InsertBuilder<T> extends ConditionBuilder<T> {
  /** 表名 */
  private tableName: string;

  /** 实体映射信息 */
  private entityMapping?: TableEntityMapping;

  /** SQL操作类型 */
  private operationType: SqlOperationType = SQL_OPERATION_TYPE.INSERT;

  /** 要插入的数据 */
  private data: Partial<T> | Partial<T>[];

  /** 是否使用REPLACE语法 */
  private useReplace: boolean = false;

  /** 是否使用OR IGNORE语法 */
  private useIgnore: boolean = false;

  /** 是否返回插入的ID */
  private returnId: boolean = false;

  /** ID列名 */
  private idColumnName: string = 'id';

  /**
   * 是否使用兼容模式
   * SQLite 3.35.0 (2021-03-12)之前的版本不支持RETURNING子句
   */
  private useLegacyMode: boolean = false;

  /**
   * 构造函数
   * @param tableName 表名
   * @param data 要插入的数据
   * @param entityMapping 实体映射信息（可选）
   * @param extensions SQL构建器扩展（可选）
   */
  constructor(
    tableName: string,
    data: Partial<T> | Partial<T>[],
    entityMapping?: TableEntityMapping,
    extensions?: SqlBuilderExtensions
  ) {
    super(undefined, extensions);
    this.tableName = tableName;
    this.data = data;
    this.entityMapping = entityMapping;

    // 如果有实体映射，自动设置ID字段
    if (entityMapping) {
      for (const propName in entityMapping.fields) {
        const field = entityMapping.fields[propName];
        if (field.isPrimaryKey && field.isAutoIncrement) {
          this.idColumnName = field.columnName;
          break;
        }
      }
    }
  }

  /**
   * 克隆当前构建器
   */
  protected clone(): InsertBuilder<T> {
    const clone = new InsertBuilder<T>(
      this.tableName,
      this.data,
      this.entityMapping,
      this.extensions
    );

    clone.conditions = [...this.conditions];
    clone.parameters = {...this.parameters};
    clone.paramCounter = this.paramCounter;
    clone.useReplace = this.useReplace;
    clone.useIgnore = this.useIgnore;
    clone.returnId = this.returnId;
    clone.idColumnName = this.idColumnName;
    clone.useLegacyMode = this.useLegacyMode;

    return clone;
  }

  /**
   * 处理字段名，增加对实体映射的支持
   * @param field 字段名
   */
  protected processFieldName(field: string): string {
    let processedField = field;

    // 如果有实体映射，转换属性名到字段名
    if (this.entityMapping && this.entityMapping.fields[field]) {
      processedField = this.entityMapping.fields[field].columnName;
    }

    return processedField;
  }

  /**
   * 使用REPLACE INTO语法
   * 如果存在唯一键冲突，先删除旧记录，再插入新记录
   */
  public replace(): this {
    this.useReplace = true;
    this.useIgnore = false;  // replace和ignore不能同时使用
    return this;
  }

  /**
   * 使用INSERT OR IGNORE语法
   * 如果存在唯一键冲突，忽略新记录
   */
  public ignore(): this {
    this.useIgnore = true;
    this.useReplace = false;  // replace和ignore不能同时使用
    return this;
  }

  /**
   * 设置兼容模式
   * 用于兼容SQLite 3.35.0以前的版本（不支持RETURNING子句）
   * @param useLegacyMode 是否使用兼容模式
   * @returns 当前构建器实例
   */
  public setLegacyMode(useLegacyMode: boolean): this {
    this.useLegacyMode = useLegacyMode;
    return this;
  }

  /**
   * 设置是否返回插入ID
   * 注意：需要SQLite 3.35.0或更高版本支持RETURNING子句
   * 对于低版本SQLite，请使用setLegacyMode(true)并通过lastInsertRowid获取ID
   * @param returnId 是否返回ID
   * @param idColumnName ID列名
   * @returns 当前构建器实例
   */
  public returning(returnId: boolean = true, idColumnName?: string): this {
    this.returnId = returnId;

    if (idColumnName) {
      this.idColumnName = idColumnName;
    }

    return this;
  }

  /**
   * 构建SQL
   */
  public build(): SqlBuildResult {
    // 应用构建前钩子
    if (this.extensions?.sqlHooks?.beforeBuild) {
      this.extensions.sqlHooks.beforeBuild({
        operationType: this.operationType,
        tableName: this.tableName,
        data: this.data,
        useReplace: this.useReplace,
        useIgnore: this.useIgnore,
        returnId: this.returnId,
        idColumnName: this.idColumnName
      });
    }

    let sql = '';
    const isMultiInsert = Array.isArray(this.data) && this.data.length > 0;
    const dataArray = isMultiInsert ? this.data as Partial<T>[] : [this.data as Partial<T>];

    if (dataArray.length === 0) {
      throw new Error('No data provided for insert operation');
    }

    // 获取所有要插入的字段（合并所有数据对象的字段）
    const allFields = new Set<string>();
    for (const item of dataArray) {
      for (const key in item) {
        if (Object.prototype.hasOwnProperty.call(item, key)) {
          allFields.add(key);
        }
      }
    }

    const fieldNames: string[] = [];
    for (const field of allFields) {
      fieldNames.push(this.processFieldName(field));
    }

    // 确定INSERT语句类型
    if (this.useReplace) {
      sql = 'REPLACE INTO ';
    } else if (this.useIgnore) {
      sql = 'INSERT OR IGNORE INTO ';
    } else {
      sql = 'INSERT INTO ';
    }

    // 添加表名和字段列表
    sql += `${this.tableName} (${fieldNames.join(', ')})`;

    // 构建VALUES部分
    const valuesClauses: string[] = [];

    for (let i = 0; i < dataArray.length; i++) {
      const data = dataArray[i];
      const paramPlaceholders: string[] = [];

      for (const field of allFields) {
        const paramName = this.generateParamName(`${field}_${i}`);
        paramPlaceholders.push(`@${paramName}`);

        // 如果该条数据中有这个字段，使用该值，否则使用null
        if (Object.prototype.hasOwnProperty.call(data, field)) {
          this.parameters[paramName] = this.processValue(data[field as keyof typeof data]);
        } else {
          this.parameters[paramName] = null;
        }
      }

      valuesClauses.push(`(${paramPlaceholders.join(', ')})`);
    }

    sql += ` VALUES ${valuesClauses.join(', ')}`;

    // 如果要返回ID，添加RETURNING子句
    if (this.returnId && !this.useLegacyMode) {
      sql += ` RETURNING ${this.idColumnName}`;
    }

    // 创建结果
    const result: SqlBuildResult = {
      sql,
      params: this.parameters
    };

    // 应用构建后钩子
    if (this.extensions?.sqlHooks?.afterBuild) {
      return this.extensions.sqlHooks.afterBuild(result, {
        operationType: this.operationType,
        tableName: this.tableName
      });
    }

    return result;
  }

  /**
   * 将实体对象转换为可插入的数据
   * @param tableName 表名
   * @param entity 实体对象
   * @param entityMapping 实体映射信息
   * @param extensions SQL构建器扩展
   */
  public static fromEntity<E extends Entity>(
    tableName: string,
    entity: E | E[],
    entityMapping?: TableEntityMapping,
    extensions?: SqlBuilderExtensions
  ): InsertBuilder<E> {
    return new InsertBuilder<E>(tableName, entity, entityMapping, extensions);
  }

  /**
   * 执行插入操作
   * @param executor 可选的SQL执行器，如果未提供则使用内部设置的执行器
   * @returns 执行结果
   */
  public execute(executor?: SqlExecutor): SqlExecuteResult {
    const result = this.build();
    const actualExecutor = executor || this.getExecutor();

    if (!actualExecutor) {
      throw new Error('No SQL executor available. Please set an executor using setExecutor() or provide one as parameter.');
    }

    return actualExecutor.execute(result.sql, result.params);
  }

  /**
   * 执行插入操作并返回最后插入的ID
   * @param executor 可选的SQL执行器，如果未提供则使用内部设置的执行器
   * @returns 最后插入的ID
   */
  public executeGetId(executor?: SqlExecutor): number | bigint | undefined {
    const result = this.execute(executor);
    return result.lastInsertRowid;
  }
}
